﻿using System.Drawing;
using CanvasControl.Interface;
using CanvasControl.Model;

namespace CanvasControl.View
{
    /// <summary>
    /// Исходное состояние.
    /// </summary>
    public class IdleState : IInputListener
    {
        public static readonly IdleState INSTANCE = new IdleState();

        IdleState()
        {
        }

        public void OnMouseDown(InputState input)
        {
        }

        public void OnMouseMove(Point p)
        {
        }

        public void OnMouseUp(Point p)
        {
        }
    }
    /*
    /// <summary>
    /// Состояние перемещения выделенного элемента.
    /// </summary>
    public class DraggingState : ViewMouseState
    {
        /// <summary>
        /// Размеры области, в рамках которой перемещение не будет инициировать перетаскивание.
        /// </summary>
        static readonly Size DRAG_TOLERANCE_SIZE = SystemMetrics.GetDragToleranceSize();

        /// <summary>
        /// Координаты точки, в которой было зафиксировано первое нажатие мыши.
        /// </summary>
        readonly Point clickPoint;

        readonly GraphModel model;

        /// <summary>
        /// Флаг, равный true, если было начато перетаскивание, иначе false.
        /// </summary>
        bool isDragging;

        /// <summary>
        /// Координаты предыдущей точки, в которой находился указатель мыши.
        /// </summary>
        Point previousPoint;

        public DraggingState(IStateContext context, Block hitBlock, Point origin)
            : base(context)
        {
            model = context.Model;
            clickPoint = previousPoint = origin;
            if (!hitBlock.IsSelected)
            {
                model.ClearSelection();
                model.Select(hitBlock);
            }
            model.MoveToTop(hitBlock);
        }

        public override void ProcessMouseMovement(Point p)
        {
            var viewPoint = model.ViewPort.ClientToGlobal(p);
            if (isDragging || (isDragging = ShouldStartDrag(viewPoint)))
                DoDrag(viewPoint);
            previousPoint = viewPoint;
        }

        /// <summary>
        /// Выполняет перетаскивание.
        /// </summary>
        /// <param name="viewPoint">Координаты курсора в системе координат представления.</param>
        void DoDrag(Point viewPoint)
        {
            foreach (var block in context.Model.GetSelectedBlocks())
                block.position.Offset(viewPoint.X - previousPoint.X, viewPoint.Y - previousPoint.Y);
            context.UpdateView();
        }

        /// <summary>
        /// Определяет, должно ли начаться перетаскивание при перемещении курсора мыши.
        /// </summary>
        /// <param name="viewPoint">Текущие координаты курсора в системе координат представления.</param>
        /// <returns>Возвращает true, если перетаскивание должно начаться, иначе false.</returns>
        bool ShouldStartDrag(Point viewPoint)
        {
            return Math.Abs(clickPoint.X - viewPoint.X) >= DRAG_TOLERANCE_SIZE.Width || (Math.Abs(clickPoint.Y - viewPoint.Y) >= DRAG_TOLERANCE_SIZE.Height);
        }
    }

    /// <summary>
    /// Состояние отрисовки соединительной линии.
    /// </summary>
    public class LinkingState : ViewMouseState, IPainter
    {
        readonly Slot slot;
        readonly Point startPoint;
        readonly GraphModel model;

        Point endPoint;

        public LinkingState(IStateContext context, Slot slot)
            : base(context)
        {
            this.slot = slot;
            model = context.Model;

            var rect = slot.GetBounds();
            startPoint = model.ViewPort.GlobalToClient(new Point(rect.X + rect.Width/2, rect.Y + rect.Height/2));
            endPoint = startPoint;

            MarkSlots(slot);
            //TODO: add tooling to draw 
//            context.ViewPort.AddDrawer(this);
        }

        public override void ProcessMouseMovement(Point p)
        {
            endPoint = p;
            context.UpdateView();
        }

        public override void ProcessMouseUp(Point p)
        {
            var hit = model.HitTest(p);
            if (hit.hitType == HitType.SLOT && model.CanConnect(slot, hit.slot))
                model.Connect(slot, hit.slot);
            foreach (var b in model.EnumerateBlocks())
            foreach (var s in b.Slots)
                s.state = SlotState.DEFAULT;
            //TODO add tooling to draw
//            context.ViewPort.RemoveDrawer(this);
        }

        /// <summary>
        /// Проверяет слоты блоков, отличных от текущего, может ли быть установлено соединение между ними и текущим слотом.
        /// Маркирует состояния слотов.
        /// </summary>
        void MarkSlots(Slot currentSlot)
        {
            foreach (var otherBlock in model.EnumerateBlocks())
            foreach (var otherSlot in otherBlock.Slots)
                otherSlot.state = model.CanConnect(currentSlot, otherSlot) ? SlotState.ACCEPTABLE : SlotState.UNACCEPTABLE;
            currentSlot.state = SlotState.PRESSED;
        }

        void IPainter.Draw(DrawingContext dc)
        {
            var temp = dc.Graphics.BeginContainer();
            try
            {
                dc.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
                var painter = dc.Painters.LinkingLinePainter;
                painter.Draw(dc.Graphics, startPoint, endPoint);
            }
            finally
            {
                dc.Graphics.EndContainer(temp);
            }
        }
    }
     */
}